package com.spring;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

public class HjwApplicationContext {
    private Class configClass;

    private ConcurrentHashMap<String,Object> map=new ConcurrentHashMap<>();
    private ConcurrentHashMap<String,BeanDefinition> BeanDefinitionMap=new ConcurrentHashMap<>();
    private List<BeanPostProcessor> beanPostProcessorArrayList=new ArrayList<>();

    public HjwApplicationContext(Class configClass) {
        this.configClass = configClass;
        //扫描注解路径---获取注解下的 包 ----beandefinition---放入beandefinitionmap
        scan(configClass);
    // 创建bean   （单例）

        for (String beanName : BeanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = BeanDefinitionMap.get(beanName);
            if(beanDefinition.getScope().equals("singleton")){
                //创建bean
                Object bean = createBean( beanName,beanDefinition);
                //放入单例池
                map.put(beanName,bean);
            }

        }

    }

    public Object createBean(String beanName,BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getClazz();
        Object o = null;
        try {
            o = clazz.getDeclaredConstructor().newInstance();
            //依赖注入
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                if(declaredField.isAnnotationPresent(Autowired.class)){
                    //属性对象
                    Object bean = getBean(declaredField.getName());
                    declaredField.setAccessible(true);
                    //赋值  1 赋给那个对象  2 赋什么值
                    declaredField.set(o,bean);
                }
            }
            //将bean name赋值给自己的属性  （Aware 回调）
            if(o instanceof BeanNameAware){
                ((BeanNameAware) o).setName(beanName);
            }


            // BeanPostProcessor  初始化前
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorArrayList) {
                beanPostProcessor.postProcessBeforeInitialization(o,beanName);
            }

            //初始化
            if(o instanceof InitializingBean){
                ((InitializingBean) o).afterPropertiesSet();
            }

            // BeanPostProcessor  初始化后
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorArrayList) {
                beanPostProcessor.postProcessAfterInitialization(o,beanName);
            }


        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return o;
    }

    private void scan(Class configClass) {
        //拿到配置类  解析配置类
        ComponentScan componentScan = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
        String value = componentScan.value();//扫描路径  com.hjw.service
        String replace = value.replace(".", "/");

        //找出 路径下的类
        // Bootstrap--》 jre/lib
        // app -->classpath
        //利用类加载器  加载文件
        ClassLoader loader = HjwApplicationContext.class.getClassLoader();
        URL resource = loader.getResource(replace);

        File file= new File(resource.getFile());
        if(file.isDirectory()){
            File[] files = file.listFiles();
            for (File f : files) {
                String path = f.getAbsolutePath();
                if(path.endsWith(".class")){

                    String s = path.substring(path.indexOf("com"), path.indexOf(".class")).replace("\\",".");
                    Class<?> aClass = null;
                    try {
                        aClass = loader.loadClass(s);
                        if(aClass.isAnnotationPresent(Component.class)){

                            // BeanPostProcessor 后置处理器  放入spring
                            if(BeanPostProcessor.class.isAssignableFrom(aClass)){
                                BeanPostProcessor o = (BeanPostProcessor) aClass.getDeclaredConstructor().newInstance();
                                beanPostProcessorArrayList.add(o);
                            }


                            //扫描的包有我的注解   进行处理 创建bean对象
                            //判断是否是  单例bean  是就放入map中
                           String beanName = aClass.getDeclaredAnnotation(Component.class).value();

                            BeanDefinition beanDefinition = new BeanDefinition();
                            if(aClass.isAnnotationPresent(Scope.class)){
                                beanDefinition.setClazz(aClass);
                                beanDefinition.setScope(aClass.getDeclaredAnnotation(Scope.class).value());
                            }else{
                                beanDefinition.setScope("singleton");
                                beanDefinition.setClazz(aClass);

                            }
                            //将  beanDefinition 放入bean定义map中
                                BeanDefinitionMap.put(beanName,beanDefinition);
                        }
                    } catch (ClassNotFoundException | NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }


                }
            }
        }
    }

    public Object getBean(String beanName){
        if(BeanDefinitionMap.containsKey(beanName)){
            BeanDefinition beanDefinition = BeanDefinitionMap.get(beanName);
            if(beanDefinition.getScope().equals("singleton")){
                Object o = map.get(beanName);
                return o;
            }else{
                // 不是单例bean  创建一个bean 后返回
                //创建bean
                Object bean = createBean(beanName,beanDefinition);

            }

        }else{
            throw new NullPointerException("不存在这个bean对象");
        }
        return  null;
    }
}
